/*
 *    Copyright 2014 Sam Y Ge
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.strx;

/**
 * <p>
 * 标签处理器。
 * </p>
 * 
 * <p>
 * 通过XmlParser在解析过程中产生的Status来驱动结果对象封装过程<br/>
 * 调用者必须自己定义封装过程
 * </p>
 * 
 * @param <T>
 *            返回值类型
 * 
 * @see Parser#Parser(String, TagHandle)
 * @see Parser#Parser(Reader, TagHandle)
 * 
 * @author <a href="mailto:samuel.y@foxmail.com">Sam Y Ge</a>
 * 
 */
public class TagHandler<T> {
	/* 是否继续解析 */
	private boolean needContinue = true;

	/* 是否在本轮后移除 */
	private boolean need2Remove = false;

	/* 处理结果 */
	private T result;

	/* 异步操作是否进行中 */
	boolean processing = true;

	/**
	 * 事件通知处理
	 * 
	 * @param status
	 *            状态
	 * @param type
	 *            事件类型
	 * 
	 * @return 是否继续执行解析
	 */
	final boolean notifyProcess(Status status, TagType type) {
		try {
			switch (type) {
			case START:
				onStart(status);
				break;
			case END:
				onEnd(status);
				break;
			case CDATA:
				onCData(status);
				break;
			default:
			}
		} catch (Exception e) {
			// DO NOTHING HERE!
		}

		return needContinue;
	}

	/**
	 * <p>
	 * 处理开始标签。
	 * </p>
	 * 
	 * <p>
	 * 当读取到开始标签时触发本方法
	 * </p>
	 * 
	 * @param status
	 *            当前状态
	 */
	protected void onStart(Status status) // NOPMD SEE COMMENT
	{
		// DO NOTHING HERE BY DEFAULT
	}

	/**
	 * <p>
	 * 处理结束标签。
	 * </p>
	 * 
	 * <p>
	 * 当读取到结束标签时触发本方法
	 * </p>
	 * 
	 * @param status
	 *            当前状态
	 */
	protected void onEnd(Status status) // NOPMD SEE COMMENT
	{
		// DO NOTHING HERE BY DEFAULT
	}

	/**
	 * <p>
	 * 处理CData标签。
	 * </p>
	 * 
	 * <p>
	 * 当读取到CData标签时触发本方法, 仅能从status中获得path和text信息， path为CData节点外部的路径， text为内部文本
	 * </p>
	 * 
	 * @param status
	 *            当前状态
	 */
	protected void onCData(Status status) // NOPMD SEE COMMENT
	{
		// DO NOTHING HERE BY DEFAULT
	}

	/**
	 * 终止解析器工作。
	 * 
	 * 直接终止解析器的工作
	 */
	protected final void terminate() {
		synchronized (this) {
			processing = false;
			notifyAll();
		}

		needContinue = false;
	}

	/**
	 * 移除本处理器。
	 * 
	 * 在本轮处理完毕后该处理器将会被移除， 若所有处理器都被移除，则解析将会被终止。
	 */
	protected final void remove() {
		synchronized (this) {
			processing = false;
			notifyAll();
		}

		need2Remove = true;
	}

	final boolean isNeed2Remove() {
		return need2Remove;
	}

	/**
	 * <p>
	 * 获得处理完毕的结果。
	 * </p>
	 * 
	 * <p>
	 * 当做同步处理时，应当直接使用getResult()方法，以免多余的资源开销
	 * </p>
	 * 
	 * @param timeout
	 *            取结果的超时时间，单位:ms
	 * 
	 * @return 处理完毕的结果
	 * 
	 * @see #getResult()
	 */
	public final T getResult(long timeout) {
		if (timeout > 0) {
			synchronized (this) {
				if (processing) {
					try {
						this.wait(timeout);
					} catch (InterruptedException e) {
					}
				}
			}
		}

		return result;
	}

	/**
	 * <p>
	 * 立即获得处理完毕的结果。
	 * </p>
	 * 
	 * <p>
	 * 当做异步处理时，请不要使用本方法，否则可能取不到正确的结果
	 * </p>
	 * 
	 * @see #getResult(long)
	 * 
	 * @return 处理完毕的结果
	 */
	public final T getResult() {
		return getResult(0);
	}

	/**
	 * <p>
	 * 对结果进行赋值。
	 * </p>
	 * 
	 * <p>
	 * 如果本方法未被正确调用，将无法得到正确的结果
	 * </p>
	 */
	protected final void setResult(T result) {
		this.result = result;
	}

	/**
	 * <p>
	 * 清理本Handle。
	 * </p>
	 * 
	 * <p>
	 * 请在具体子类中覆盖本方法，以实现对具体资源的释放，如果本方法未被正确调用，可能会导致内存浪费
	 * </p>
	 */
	public void clean() // NOPMD SEE COMMENT
	{
		// DO NOTHING HERE BY DEFAULT
	}
}
